﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_TEMPLATE_UTILS_H
#define _UXS_TEMPLATE_UTILS_H

#pragma once

#include "../BaseTypes/Types.h"

namespace UX_STL
{
namespace UXTypes
{


	//
	// Array Size
	//

	template <typename ArrayType, typename ElementType>
	struct ArraySize
	{
		enum {
			value = sizeof(ArrayType) / sizeof(ElementType)
		};
	};



	//
	// Switch Type
	//

	template <bool Switch, typename IfTrue, typename IfFalse>
	struct SwitchType {
		typedef IfFalse	type;
	};

	template <typename IfTrue, typename IfFalse>
	struct SwitchType< true, IfTrue, IfFalse > {
		typedef IfTrue	type;
	};

}	// UXTypes


namespace CompileTime
{
	using namespace UXTypes;


	//
	// Value To Type in compile time
	//

	template <typename T, T Value>
	struct ValueToType
	{
		typedef T		type;
		static const T	value = Value;
	};



	//
	// Switch Value
	//

	template <bool Switch, typename IfTrue, typename IfFalse>
	struct SwitchValue {
		typedef typename IfFalse::type	type;
		static const type	value = IfFalse::value;
	};

	template <typename IfTrue, typename IfFalse>
	struct SwitchValue< true, IfTrue, IfFalse > {
		typedef typename IfTrue::type	type;
		static const type	value = IfTrue::value;
	};



	//
	// Static Size Of
	//

	template <typename T>
	struct SizeOf
	{
		enum {
			bytes	= sizeof(T),
			bits	= bytes << 3,
		};
	};



	//
	// Enable / Disable If
	//

	template <bool Condition, typename T>
	struct EnableIf {
		typedef T	type;
	};

	template <typename T>
	struct EnableIf <false, T> {
	};

	template <bool Condition, typename T>
	struct DisableIf {
		typedef T	type;
	};

	template <typename T>
	struct DisableIf <true, T> {
	};



	//
	// And
	//

	template <bool L, typename R>
	struct And {
		static const bool	value = L and R::value;
	};

	template <typename R>
	struct And< false, R > {
		static const bool	value = false;
	};



	//
	// ValueIf
	//

	template <bool Condition, typename T, typename Value>
	struct ValueIf {
		static const T	value = Value::value;
	};
	
	template <typename T, typename Value>
	struct ValueIf< false, T, Value > {
		static const T	value = T(0);
	};

	

	//
	// AddIf
	//
	
	template <bool Condition, typename T, T Left, T Right, T Default = T(0)>
	struct AddIf {
		static const T	value = Left + Right;
	};
	
	template <typename T, T Left, T Right, T Default>
	struct AddIf< false, T, Left, Right, Default > {
		static const T	value = Default;
	};

	

	//
	// SubIf
	//
	
	template <bool Condition, typename T, T Left, T Right, T Default = T(0)>
	struct SubIf {
		static const T	value = Left - Right;
	};
	
	template <typename T, T Left, T Right, T Default>
	struct SubIf< false, T, Left, Right, Default > {
		static const T	value = Default;
	};

	

	//
	// MulIf
	//
	
	template <bool Condition, typename T, T Left, T Right, T Default = T(0)>
	struct MulIf {
		static const T	value = Left * Right;
	};
	
	template <typename T, T Left, T Right, T Default>
	struct MulIf< false, T, Left, Right, Default > {
		static const T	value = Default;
	};

	

	//
	// DivIf
	//
	
	template <bool Condition, typename T, T Left, T Right, T Default = T(0)>
	struct DivIf {
		static const T	value = Left / Right;
	};
	
	template <typename T, T Left, T Right, T Default>
	struct DivIf< false, T, Left, Right, Default > {
		static const T	value = Default;
	};



	//
	// Pair
	//

	template <	typename FirstType, FirstType First,
				typename SecondType, SecondType Second
			 >
	struct Pair
	{
		typedef Pair< FirstType, First, SecondType, Second >	Self;

		typedef FirstType		first_t;
		typedef SecondType		second_t;

		static const first_t	first	= First;
		static const second_t	second	= Second;
	};



	//
	// Is Base Of
	//

	namespace _ct_hidden_
	{
		template <typename B, typename D>
		struct Host
		{
		  operator B*() const;
		  operator D*();
		};
	}
	
	template <typename Base, typename Derived>
	struct IsBaseOf
	{
	private:
		typedef uint8	_yes;
		typedef uint16	_no;

		template <typename T> 
		static _yes _check (Derived *, T);
		static _no  _check (Base *, int);

	public:
		static const bool	value = sizeof( _check( _ct_hidden_::Host< Base, Derived >(), int() ) ) == sizeof(_yes);
	};


}	// CompileTime
}	// UX_STL

#endif	// _UXS_TEMPLATE_UTILS_H